package com.dayu.finecomm.protocol.hd72;

import java.util.Calendar;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.dayu.finecomm.protocol.codec.Protocol;
import com.dayu.finecomm.protocol.codec.ProtocolDecoder;
import com.dayu.finecomm.protocol.pojo.TPacket;
import com.dayu.finecomm.protocol.pojo.TPacket.VType;
import com.dayu.finecomm.protocol.pojo.TSensor;

import io.netty.buffer.ByteBuf;

/**
 * 二次供水设备通信协议
 */
@Protocol(X0D0ADecoder.PROTO)
public class X0D0ADecoder extends ProtocolDecoder<TPacket> {

	static final String PROTO = "HD72";

	private static final int P = 0;
	private static final int K = 1;
	private static final int A = 2;
	private static final int Q = 3;
	private static final int M = 4;

	private static final int MAGIC = 0x0D0A;
	static Logger LOGGER = LoggerFactory.getLogger(X0D0ADecoder.class);

	@Override
	public int check(ByteBuf in) {

		if (in.readableBytes() < 22)
			return -1;

		// 协议头校验
		int c = in.readUnsignedShort();

		if (c != MAGIC) // 协议头
			return -1;

		int func = in.readUnsignedByte(); // 功能码

		if (func != 0x03 && func != 0x04)
			return -1;

		in.readUnsignedShort(); // sn
		// int sn = in.readUnsignedShort();

		int length = in.readUnsignedShort() + 4;

		int v = in.readUnsignedByte(); // 通讯协议版本

		if (v != 0x01)
			return -1;

		int hv = in.readUnsignedByte(); // 设备型号
		if (hv != 0x58)
			return -1;

		// 协议尾校验
		ByteBuf b = in.slice(length - 2, 2);
		if (b.readUnsignedShort() != 0x0d0a)
			return -1;

		b = in.slice(0, length - 2);

		/*
		 * //FIXME: bad CRC // CRC校验 int crc = 0;
		 * 
		 * for (int i = 2; i < length - 3; i++) { crc = crc ^
		 * b.readUnsignedByte(); }
		 * 
		 * crc = ~(crc + sn); crc = (0xff & crc) ^ b.readUnsignedByte();
		 * 
		 * if (crc != 0) return -1;
		 */

		return length;
	}

	@Override
	public TPacket unpack(ByteBuf in) {

		in.skipBytes(3); // 0D DA , 功能码

		int sn = in.readUnsignedShort();

		int length = in.readUnsignedShort() + 4; // length

		in.skipBytes(3);

		int nYear = 2000 + in.readUnsignedByte();
		int nMonth = in.readUnsignedByte() - 1;
		int nDay = in.readUnsignedByte();
		int nHour = in.readUnsignedByte();
		int nMinute = in.readUnsignedByte();
		int nSecond = 0;

		Calendar c = Calendar.getInstance();
		c.set(nYear, nMonth, nDay, nHour, nMinute, nSecond);
		c.set(Calendar.MILLISECOND, 0);

		long sTime = c.getTime().getTime();

		TPacket s = new TPacket(VType.RRR, PROTO, sn, sTime);

		in.skipBytes(1); // 通道数量

		int signal = in.readUnsignedByte(); // 信号强度
		s.sensors.add(new TSensor("S", signal, sTime));

		int h = in.readUnsignedShort(); // 上发次数
		s.sensors.add(new TSensor("H", h, sTime));

		for (; in.readerIndex() < length - 3;) {

			int no = in.readUnsignedByte();
			int type = in.readUnsignedByte();

			String channel;

			switch (type) {
			case P:
				channel = "P" + no;
				break;
			case K:
				channel = "K" + no;
				break;
			case A:
				channel = "A" + no;
				break;
			case Q:
				channel = "Q" + no;
				break;
			case M:
				channel = "M" + no;
				break;
			default:
				return null;
			}

			switch (type) {
			case P: // P通道
			{
				int val = in.readInt();
				s.sensors.add(new TSensor(channel, val, sTime));
			}
				break;
			case K: // K通道
			{
				int val = in.readUnsignedByte();
				s.sensors.add(new TSensor(channel, val, sTime));
			}
				break;
			case A:// A通道
			{
				float val = Float.intBitsToFloat(Integer.reverseBytes(in.readInt()));
				s.sensors.add(new TSensor(channel, val, sTime));
			}
				break;
			case Q:// Q通道
			{

				for (int j = 0, k = in.readUnsignedShort(); j < 15; j++, k >>>= 1) {

					int val = k & 1;
					s.sensors.add(new TSensor(channel + "_" + j, val, sTime));
				}
			}
				break;
			case M: // M通道
			{

				for (int j = 1; j < 5; j++) {

					short k = in.readUnsignedByte();

					s.sensors.add(new TSensor(channel + "_" + (2 * j - 1), (k >>> 4), sTime));
					s.sensors.add(new TSensor(channel + "_" + (2 * j), (k & 0xff), sTime));
				}
			}
				break;
			default:
				return null;
			}
		}

		return s;
	}

	@Override
	public int checkStart(ByteBuf in) {
		return 0;
	}

	@Override
	public Object timing() {
		return HD72Convention.timing();
	}

	@Override
	public byte[] echo() {
		return "@222".getBytes();
	}
}
